#ifndef CMDLINEPARSER_H_JM_20130111
#define CMDLINEPARSER_H_JM_20130111
/// @file CmdLineParser.h 
/// Parser argumentov program z prikazoveho riadku.

#include "CmdLineOptionExceptions.h"
#include "CmdLineOption.h"

namespace jmlib {

	/// CmdLineParser je parser argumentov prikazoveho riadku programu.
	class  CmdLineParser {
	public:

		virtual ~CmdLineParser() { }
		
		/// Pridanie definicie prepinaca do parseru.
		/// parser akceptuje len prepinace, ktore su pridane pomocou tejte 
		/// metody.
		CmdLineOptionDefinition& addOptionDefinition(const std::string& name, 
			CmdLineOptionDefinition::ValuePresence values = CmdLineOptionDefinition::NONE);

		/// Parsovanie argumentov z prikazoveho riadku.
		void parseCmdLine(int argc, char *argv[]);

		/** Detekcia sparsovania prepinaca podla mena prepinaca.
		 *
		 * @return Ukazovatel na sparsovany prepinac pripadne nulptr okial  
		 * prepinac so zadanym menom nebol sparsovany (nenachdzal sa na 
		 * prikazovom riadku).
		 * 
		 * @throw CmdLineOptionNotFoundException Pokial nie je oprion 
		 * definovany resp. pridany pomocou addOptionDefinition.
		 **/
		CmdLineOptionInstance* operator[](const std::string& name);


		/**
		 * Zresetovanie parseru na stav totozny so stavom priamo po konstrukcii.
		 **/
		void resetParser();

		/// Pocet najdeny izolovanych argumentov.
		size_t isolatedArgsCount() const { return isolatedArgs_.size(); }

		/// Hodnota izolovaneho arguementu najdeneho na i-tej pozicii.
		const std::string& getIsolatedArg(const size_t i) const { 
			return isolatedArgs_.at(i); 

		}
	protected:
		
		/// Typ kontaineru na prepinace prikazoveho riadku.
		typedef std::vector<CmdLineOption> CmdLineOptionContainer;
		
		/// Vrati prepinac podla mena, vyhladanie prepinacov prebieha aj medzi 
		/// aliasmy.
		/// @throw CmdLineOptionNotFoundException Pokial nie je oprion 
		/// definovany resp. pridany pomocou addOptionDefinition.
		CmdLineOption* getOption(const std::string& name);		
		
		/// Obsahuje predany retazec option? 
		/// Jedna sa teda retazec zacinajuci - alebo --, ktory ma minimalne 
		/// 2 znaky resp. 3.
		bool isOption(const std::string& arg) const;
		
		/// Vrati normalizovany nazov prepinacu (bez prefixu - alebo --).
		std::string normalizeOption(const std::string& name);
		
		/// Zapamatanie izolovaneho argumentu prikaozveho riadku.
		/// Izolovany argument je argument, ktori nie je prepinac a ani napatri 
		/// k ziadnemu prepinacu ako rozsirujuca hodnota.
		void addIsolatedArg(const std::string& arg);
		
	private:
		/// Kontainer definicii prepinacov s pripadnymi instanciami najdenymi 
		/// na priakzovom riadku. Insatncie su doplnene az po naparsovani 
		/// pomocou  {@link parseCmdLine(int argc, char *argv[])}.
		CmdLineOptionContainer args_;
		
		/// Izolovane argumenty najdene na prikazovom riadku.
		/// Naplnene az po naparsovani pomocou 
		/// {@link parseCmdLine(int argc, char *argv[])}.
		std::vector<std::string> isolatedArgs_;

		/// Priadnie doplnujucej hodnboty prepinacu alebo ulozenie izolovaneho 
		/// arguemntu.
		/// Pokial je opt == nulptr alebo pokial nie su z definicie opt 
		/// pripustne rozsirujuce hodnoty tak sa ulozi value ako izolovany 
		/// argument. Inak sa value ulozi do opt ako rozsirujuca hodnota.
		void addOptionValueOrIsolatedArg(CmdLineOption* opt, const char* value);
	};
} // namespace jmlib

#endif
